package com.gitee.xmhzzz.component.web.filter;

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.List;

/**
  * @ClassName
  * @Description HttpLogFilter
  * @Author wzq
  * @Date 2023/12/18 10:22
  * @Version 1.0
  */
@Slf4j
public  class HttpLogFilter extends OncePerRequestFilter {


    public static final String SPLIT_STRING_M = "=";
    public static final String SPLIT_STRING_DOT = ", ";


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {

        // 判断请求方式
        String method = request.getMethod();
        String uriPath = request.getRequestURI();
        String[] split = uriPath.split("/");
        List<String> strings = Lists.newArrayList(split);
        if (strings.contains("doc.html") ||
                strings.contains("webjars") ||
                strings.contains("swagger-resources") ||
                strings.contains("api-docs")
        ){
            log.info("{} 请求进入 URI:{} ", method, uriPath);
            filterChain.doFilter(request, response);
        } else {
            BodyReaderHttpServletRequestWrapper wrapperRequest = new BodyReaderHttpServletRequestWrapper(request);
            ContentCachingResponseWrapper wrapperResponse = new ContentCachingResponseWrapper(response);
            String requestBodyStr = HttpHelper.getBodyString(wrapperRequest);
            String urlParams = getRequestParams(request);
            long startTime = System.currentTimeMillis();
            log.info("{} 请求进入 URI:{} start:{} params[{}] | request body:{}", method, uriPath,startTime, urlParams, requestBodyStr);
            filterChain.doFilter(wrapperRequest, wrapperResponse);
            String responseBodyStr = getResponseBody(wrapperResponse);
            long endTime = System.currentTimeMillis();
            log.info("{} 请求进入 URI:{} end:{} time:{} response body:{}", method, uriPath,endTime,endTime-startTime,responseBodyStr);
            wrapperResponse.copyBodyToResponse();
        }
    }

    /**
     * 打印请求参数
     *
     * @param request
     */
    private String getRequestBody(ContentCachingRequestWrapper request) {
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper != null) {
            byte[] buf = wrapper.getContentAsByteArray();
            if (buf.length > 0) {
                String payload;
                try {
                    payload = new String(buf, 0, buf.length, Charset.forName("UTF-8"));
                } catch (Exception e) {
                    payload = "[unknown]";
                }
                return payload.replaceAll("\\n", "");
            }
        }
        return "";
    }

    /**
     * 打印返回参数
     *
     * @param response
     */
    private String getResponseBody(ContentCachingResponseWrapper response) {
        ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response,
                ContentCachingResponseWrapper.class);
        if (wrapper != null) {
            byte[] buf = wrapper.getContentAsByteArray();
            if (buf.length > 0) {
                String payload;
                try {
                    payload = new String(buf, 0, buf.length, Charset.forName("UTF-8"));
                } catch (Exception e) {
                    payload = "[unknown]";
                }
                return payload;
            }
        }
        return "";
    }

    /**
     * 获取请求地址上的参数
     *
     * @param request
     * @return
     */
    public static String getRequestParams(HttpServletRequest request) {
        StringBuilder sb = new StringBuilder();
        Enumeration<String> enu = request.getParameterNames();
        //获取请求参数
        while (enu.hasMoreElements()) {
            String name = enu.nextElement();
            sb.append(name + SPLIT_STRING_M).append(request.getParameter(name));
            if (enu.hasMoreElements()) {
                sb.append(SPLIT_STRING_DOT);
            }
        }
        return sb.toString();
    }


}

